using System;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;
using System.Collections.Generic;

using ZoneFiveSoftware.Common.Data;
using ZoneFiveSoftware.Common.Data.Fitness;
using ZoneFiveSoftware.Common.Data.Measurement;
using ZoneFiveSoftware.Common.Data.GPS;
using ZoneFiveSoftware.Common.Visuals;
//using BENBUN.ExportCRS.Xml.Topografix.Gpx11;
using BENBUN.ExportCRS.Xml.Garmin;

namespace BENBUN.ExportCRS
{
    partial class  ExportRouteToCRSAction : IAction
    {
        public ExportRouteToCRSAction(IRoute route)
        {
            this.route = route;
        }

        #region IAction Members

        public bool Enabled
        {
            get { return route != null && route.GPSRoute.Count > 0; }
        }

        public bool HasMenuArrow
        {
            get { return false; }
        }

        public Image Image
        {
            get { return Properties.Resources.Image_16_Export; }
        }

        public void Refresh()
        {
        }

        public void Run(Rectangle rectButton)
        {
            crsExportForm getD = new crsExportForm();
            getD.ShowDialog();
            if (getD.doExport == DialogResult.Yes)
            {
                try
                {
                    Export(BenbunPlugin.Instance.exportFileName);
                    MessageBox.Show("The CRS Extract file has been created", "Export Complete", MessageBoxButtons.OK);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

        public string Title
        {
            get { return Properties.Resources.Edit_ExportRouteToCRSAction_Text; }
        }

        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        private void Export(string filename)
        {
            int now_y = DateTime.Today.Year;
            int now_m = DateTime.Today.Month;
            int now_d = DateTime.Today.Day;
            int now_hh = DateTime.UtcNow.Hour;
            int now_mm = DateTime.UtcNow.Minute;
            int now_ss = DateTime.UtcNow.Second;
            double totalDistance = 0;
            double thisDistance = 0;
            double thisMaxDistance = 0;

            startTime = new DateTime(now_y,now_m,now_d,now_hh,now_mm,now_ss);

            //
            // Work out secs poer meter for speed.
            float secsPerMeter = 0.00000F;

            switch( BenbunPlugin.Instance.export_speedUnits)
            {
                case 0: // miles per hour
                    secsPerMeter = 0.44704F;
                    secsPerMeter = (secsPerMeter * (float)BenbunPlugin.Instance.export_speed);
                    secsPerMeter = 1 / secsPerMeter;
                    break;
                case 1: // km per hour
                    secsPerMeter = 0.27777F;
                    secsPerMeter = (secsPerMeter * (float)BenbunPlugin.Instance.export_speed);
                    secsPerMeter = 1 / secsPerMeter;
                    break;
                case 2: // mins per mile
                    secsPerMeter = ((1 / (float)BenbunPlugin.Instance.export_speed) / 60) * 1609.34f;
                    secsPerMeter = 1 / secsPerMeter;
                    break;
                case 4: // mins per km
                    secsPerMeter = ((1 / (float)BenbunPlugin.Instance.export_speed) / 60) * 1000;
                    secsPerMeter = 1 / secsPerMeter;
                    break;
                default :
                    secsPerMeter = 0.27777F *(float)BenbunPlugin.Instance.export_speed;
                    secsPerMeter = 1 / secsPerMeter;
                    break;
            }

            if (BenbunPlugin.Instance.distanceUnits == "meter")
            {
                thisMaxDistance = BenbunPlugin.Instance.maxLength;
            }
            else
            {
                thisMaxDistance = BenbunPlugin.Instance.maxLength * 0.3048;
            }

            //
            // Build the xml data.   
            
            TrainingCenterDatabase_t crsExport = new TrainingCenterDatabase_t();
            Courses_t crsCourses = new Courses_t();
            crsExport.Courses = crsCourses;
            CourseFolder_t crsCourseFolder = new CourseFolder_t();
            crsCourseFolder.Name = "Exported from SportTracks Route with ExportCRS";
            crsExport.Courses.CourseFolder = crsCourseFolder;

            Course_t crsCourse = new Course_t();
            crsCourse.Notes = route.Notes;

            if (BenbunPlugin.Instance.nameSourceLocation == "location")
            {
                crsCourse.Name = route.Location;
                if (crsCourse.Name.Trim() == "")
                {
                    crsCourse.Name = route.Name;
                }
            }
            else
            {
                crsCourse.Name = route.Name;
                if (crsCourse.Name.Trim() == "")
                {
                    crsCourse.Name = route.Location;
                }
            }


            if (crsCourse.Name.Trim() == "")
            {
                crsCourse.Name = "Course Name";
            }

            if (crsCourse.Name.Length > 15)
            {
                crsCourse.Name = crsCourse.Name.Substring(0, 15);
            }
            
            CourseLap_t crsLap = new CourseLap_t();
            crsLap.TotalTimeSeconds = route.GPSRoute.TotalElapsedSeconds;
            crsLap.DistanceMeters = route.GPSRoute.TotalDistanceMeters;
            crsLap.Intensity = Intensity_t.Active;


            Position_t crsBeginPosition = new Position_t();
            Position_t crsEndPosition = new Position_t();
            
            IGPSRoute GPSRouteLocal = route.GPSRoute;

            ITimeValueEntry<IGPSPoint> GPSStartPoint = GPSRouteLocal[0];
            ITimeValueEntry<IGPSPoint> GPSEndPoint = GPSRouteLocal[GPSRouteLocal.Count - 1];

            crsBeginPosition.LatitudeDegrees = GPSStartPoint.Value.LatitudeDegrees;
            crsBeginPosition.LongitudeDegrees = GPSStartPoint.Value.LongitudeDegrees;

            crsEndPosition.LatitudeDegrees = GPSEndPoint.Value.LatitudeDegrees;
            crsEndPosition.LongitudeDegrees = GPSEndPoint.Value.LongitudeDegrees;

            ////
            //// Take care with the altitude as it is possible none have been added 
            //// to the route
            ////
            crsLap.BeginPosition = crsBeginPosition;
            crsLap.EndPosition = crsEndPosition;
            if (!float.IsNaN(GPSStartPoint.Value.ElevationMeters))
            {
                crsLap.BeginAltitudeMeters = GPSStartPoint.Value.ElevationMeters;
                crsLap.BeginAltitudeMetersSpecified = true;
            }
            if (!float.IsNaN(GPSEndPoint.Value.ElevationMeters))
            {
                crsLap.EndAltitudeMeters = GPSEndPoint.Value.ElevationMeters;
                crsLap.BeginAltitudeMetersSpecified = true;
            }
            crsCourse.Lap = new CourseLap_t[] { crsLap };

            //
            // Deal with the trackpoints

            
            Track_t crsTrack = new Track_t();
            
            ITimeValueEntry<IGPSPoint> priorEntry = null;
            //ITimeValueEntry<IGPSPoint> newPoint = null;
            GPSUtils GPSUtilities = new GPSUtils();
            
            List<Trackpoint_t> trackpoints = new List<Trackpoint_t>();

            priorEntry = null;

            foreach (ITimeValueEntry<IGPSPoint> entry in route.GPSRoute)
            {

                Trackpoint_t new_trackpoint = new Trackpoint_t();
                Position_t new_position = new Position_t();

                if (priorEntry != null)
                {
                    thisDistance = priorEntry.Value.DistanceMetersToPoint(entry.Value);
                    totalDistance += thisDistance;
                }

                if ((thisDistance > thisMaxDistance) && (BenbunPlugin.Instance.doMaxLength))
                {

                    trackpoints.AddRange(GPSUtilities.CreateNewPoints(priorEntry,entry,thisDistance,thisMaxDistance));
                }

                //if (BenbunPlugin.Instance.originalTime)
                //{
                  
                new_trackpoint.Time = startTime.AddSeconds(Math.Round(((double)secsPerMeter * totalDistance)));
                new_position.LatitudeDegrees = entry.Value.LatitudeDegrees;
                new_position.LongitudeDegrees = entry.Value.LongitudeDegrees;
                new_trackpoint.Position = new_position;
                if (!double.IsNaN(entry.Value.ElevationMeters))
                {
                    new_trackpoint.AltitudeMeters = entry.Value.ElevationMeters;
                    new_trackpoint.AltitudeMetersSpecified = true;
                }

                trackpoints.Add(new_trackpoint); 
                priorEntry = entry;
            }
            
            crsTrack.Trackpoint = trackpoints.ToArray();
            crsCourse.Track = new Track_t[] { crsTrack };
            
            //
            // Add the
            //
            List<CoursePoint_t> coursePoints = new List<CoursePoint_t>();
            if (BenbunPlugin.Instance.doTurns) coursePoints.AddRange(GPSUtilities.CreateTurnPoints(crsTrack.Trackpoint));
            if (BenbunPlugin.Instance.doValleys) coursePoints.AddRange(GPSUtilities.CreateValleys(crsTrack.Trackpoint));
            if (BenbunPlugin.Instance.doSummits) coursePoints.AddRange(GPSUtilities.CreateSummits(crsTrack.Trackpoint));

            crsCourse.CoursePoint = coursePoints.ToArray();
            crsExport.Courses.CourseFolder.Course = new Course_t[] { crsCourse };

            ////// Save the crs file.
            XmlSerializer serializer = new XmlSerializer( crsExport.GetType() );
            TextWriter writer = new StreamWriter(filename);
            serializer.Serialize(writer, crsExport);
            writer.Close();
        }

        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        

        private int IndexOfFirstAltitude(Trackpoint_t[] track)
        {
            int start = 0;
            while (start < track.Length && !track[start].AltitudeMetersSpecified)
            {
                start++;
            }

            return start == track.Length ? -1 : start;
        }
        private IRoute route = null;
        private DateTime startTime = DateTime.UtcNow;
        
    }
}
